package com.google.code.lightsomy.util;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.classreading.SimpleMetadataReaderFactory;

/**
 * Searches classes from current classloader by some annotation type.
 * 
 * @author Viktoras Agejevas
 *
 */
public class AnnotatedClassSearch {

	private static Log log = LogFactory.getLog(AnnotatedClassSearch.class);
	
	private AnnotatedClassSearch() {}
	
	public static Map<String, String> search(String pkg, Class<?> annotation) {
		if (pkg != null && !"".equals(pkg) && !"*".equals(pkg) ) {
			pkg =  System.getProperty("file.separator") + pkg.replace(".", System.getProperty("file.separator"));
		} else {
			pkg = "";
		}

		Map<String, String> result = new HashMap<String, String>();
		MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
		ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver(
		Thread.currentThread().getContextClassLoader());
		String classes = "classpath*:**" + pkg + System.getProperty("file.separator") + "*.class";
		Resource[] resources = null;
		
		try {
			resources = resourceResolver.getResources(classes);
		} catch (IOException e) {
			log.error("Failed to get the list of classes", e);
		}

		for (Resource resource : resources) {
			try {
				MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(resource);
				if(metadataReader.getAnnotationMetadata().hasAnnotation(annotation.getName())) {
					String fullClassName = metadataReader.getClassMetadata().getClassName();
					String simpleClassName = getSimpleName(fullClassName);
					result.put(simpleClassName, fullClassName);
				}
			} catch (IOException e) {
				log.error("Failure on searching annotaded class: " + resource, e);
			}
		}
		
		return result;
	}
	
	/**
	 * Returns simple class name (just class name without package).
	 * 
	 * @param className
	 * @return simple class name
	 */
	protected static String getSimpleName(String className) {
		if (className == null) {
			throw new NullPointerException("className is null");
		}
		String[] splitted = className.split("\\.");
		return splitted[splitted.length - 1];
	}
}